import { UtilsHelper } from "utils/position/UtilsHelper";
import { StructureEntity, entity_memory_cache } from "../StructureEntity";
import { SpawnLayoutConfig  } from "./spawnlayout";
import { PositionHelper } from "utils/position/PositionHelper";
 
import { Queue } from "algorithm/Queue";
import { ATeamEntity } from "../../team";
 

export class SpawnEntity<T extends ITask<ISpawnData> = ITask<ISpawnData>,U extends ISpawnMemory<T>=ISpawnMemory<T>> extends StructureEntity <U> implements ITaskExecuter<T> , ILinkModule,IStoreModule
{
 
    @entity_memory_cache()
    private tasks!:Array<T>;
    private taskQueue!: Queue<T>;
    private _cacheContainerPos:RoomPosition[]=[]
    public get spawnQueue()
    {
        return this.taskQueue
    }
    // private get tasks()
    // {
    //     return this.getNodeMemory().tasks
    // }
    
    public initAttributes(): void {
        super.initAttributes();
        const compare = (a:T,b:T)=>{
            
            return a.priority > b.priority;
        }
        const prioritygetter = (a:T )=>{
            
            return a.priority 
        }
        if(!this.getNodeMemory().workmap)
        {
            this.getNodeMemory().workmap={};
        }
        if(!this.getNodeMemory().filler)
        {
            this.getNodeMemory().filler={};
        }
        if(!this.getNodeMemory().tasks)
        {
            this.getNodeMemory().tasks=[];
        }
        if(!this.getNodeMemory().renewSlot)
        {
            this.getNodeMemory().renewSlot={};
        }
        const _this = this;
        this.taskQueue = new  Queue<T>({
            heapgetter:{
            getHeap()
            {
                return _this.tasks
            },
            setHeap(val:T[])
            {
                _this.tasks= val;
            }
        }
        // initialElements:_this.tasks
        ,comparator:prioritygetter});
   
 
       
       // if(!this.getNodeMemory().spawnstats)
        {
            this.getNodeMemory().spawnstats = this.getSpawnStatus();
            //global.Log.Debug(`${this.GUID()} 初始化孵化状态`,JSON.stringify( this.getSpawnStatus()));
            //global.Log.Debug(`${this.GUID()} 初始化时的任务数量个数`,JSON.stringify( this.tasks.map(e=>{return {p:e.data.priority,role:e.data.spawn_info[0].bodyconfig.Role}})));
        }
        {
            this._cacheContainerPos = SpawnLayoutConfig.containeridx.map(e=> this.getAbsulotePosition(e))
        }
    }
    /**
     * 更新内存属性
     */
    public updateMemory(): void 
    {
        const memory = this.getNodeMemory();
        for( const x in SpawnLayoutConfig.ExtensionAndSpawnMap)
        {
            for(const y in  SpawnLayoutConfig.ExtensionAndSpawnMap[x])
            {
                const p:IFVector2 = {x:parseInt(x),y:parseInt(y)};
                const extensions:Id<StructureExtension |StructureSpawn>[] = this.getStructuresByRelative(STRUCTURE_EXTENSION,SpawnLayoutConfig.ExtensionAndSpawnMap[x][y],PositionHelper.addPosition(this.BasePosition,p));
                const spawns:Id<StructureExtension |StructureSpawn>[]  = this.getStructuresByRelative(STRUCTURE_SPAWN,SpawnLayoutConfig.ExtensionAndSpawnMap[x][y],PositionHelper.addPosition(this.BasePosition,p));
                memory.workmap[SpawnLayoutConfig.formatVector(p)] =extensions.concat(spawns);
            }
        }
     
        const spawn = this.spawnStructures();
       
        if(Object.keys(memory.renewSlot).length<spawn.length)
        {
            for(const e of spawn)
            {
                const spawn = e;
                if(!memory.renewSlot[spawn.name])
                {
                    memory.renewSlot[spawn.name]=undefined;
                }
            }
            
        }
    }
    public addTask(task: T): number 
    {
        if( this.taskQueue.size()>40)
        {
            this.log("warn",`孵化错误:孵化任务已经达到15 ${JSON.stringify(task)} ${JSON.stringify(new Error().stack)}`);
            for(let i=0;i<this.taskQueue.size();i++)
            {
                if(this.taskQueue.getAt(i).data.spawn_info.length==0)
                {
                    this.taskQueue.deleteAt(i);
                    i--;
                }
            }
            return 0
        }
        
        for(const e of task.data.spawn_info)
        {
            this.incressRoleCount(e.bodyconfig.Role,e.count);
            
        }
        this.taskQueue.push(task);
        return 1;
    }
    private isTaskExpired(task:ITask<ISpawnData>)
    {
        // if(task.data.spawn_info.length == 0)
        // {
        //     return true;
        // }
        if(task.data.teamid)
        {
            if(this.getEntityByID(task.data.teamid))
            {
                return false;
            }
            else 
            {
                Memory.Debug[`孵化错误：小队[${task.data.teamid}] 不存在 弹出任务`]=JSON.stringify(task);
                
            }
        }
        else 
        {
            if(this.room.getTaskById( task.data.OwerID,["creep","team"]))
            {
                return false
            }
            if(this.getEntityByID(task.data.OwerID))
            {
                // 有可能是没有绑定任务ID的任务 比如 filler 和 manager 。这里可能需要改进一下。作为一个房间运营任务
                return false;
            }
        }
        return true
    }
    private addNewCreep(spawndata: ISpawnData,index:number)
    {
        
        if(Game.cpu.bucket<1 &&  Game.cpu.limit-Game.cpu.getUsed()<1)
        {
            // 保证状态更新成功
            return false
        }
        const spawninfo = spawndata.spawn_info[index];
        if(spawninfo.creepName  )
        {
            if(spawninfo.creepName.length)
            {
                const creep = Game.creeps[spawninfo.creepName[0]];
                if(!creep)
                {
                    return false;
                }
                // 孵化完成
                if(spawndata.teamid )
                {
                    
                    const entity = this.getEntityByID<ATeamEntity>(spawndata.teamid);
                    if(entity)
                    {
                       
                        entity.addCreep([creep]);
                        this.spliceSpawnInfo(spawndata,index);
                        
                    }
                }
                else 
                {
                    this.room.addCreep(creep.name,spawninfo.bodyconfig.Role);
                    this.spliceSpawnInfo(spawndata,index);
                   
                }
                this.decressRoleCount(spawninfo.bodyconfig.Role);
                return true
            }
            else 
            {
                if(spawninfo.creepName.length == 0 && spawninfo.count ==0)
                {
                    this.spliceSpawnInfo(spawndata,index);
                    return true;
                }
            }
            
        }
        return false;
    }
    public checkExpireTask()
    {
        let nextSpawnTask = this.spawnQueue.top();
         
        while(nextSpawnTask)
        {
            if(this.isTaskExpired(nextSpawnTask))
            {
                nextSpawnTask = this.spawnQueue.pop() as T;
                
                if(nextSpawnTask)
                {
                    for(const e of nextSpawnTask.data.spawn_info)
                    {
                        this.decressRoleCount(e.bodyconfig.Role);
                    }
                }
            }
            else
            {
                // global.Log.Info(`assertC`);
                for(let i=0;i<nextSpawnTask.data.spawn_info.length;)
                {
                    if(this.addNewCreep(nextSpawnTask.data,i) )
                    {        
                                         
                    }
                    else
                    {
                        i++;
                    }
                }
                if(nextSpawnTask.data.spawn_info.length==0)
                {
                    this.spawnQueue.pop();
                    nextSpawnTask=this.spawnQueue.top();
                }
                else
                {
                    break;
                }
            }
            
        }
    }
    /**
     * 根据guid 查找这个guid发起的孵化任务
     * @param guid 
     */
    public getTasksByOwner(guid:string)
    {
        return this.tasks.find(e=>e.data.OwerID == guid);
    }
    public deleteTasksByOwner(guid:string)
    {
        for(let i=0;i<this.tasks.length;i++)
        {
            if(this.tasks[i].data.OwerID == guid)
            {
                this.tasks.splice(i,1);
                i--
            }
        }
         
    }
    /**
     * 获取正在孵化的角色数量
     * @param role 
     * @param id 
     * @returns 
     */
    public getSpawnCountByRole(role:RoleName,id?:string)
    {
        const memory = this.getNodeMemory();
        if(id)
        {
            let count=0;
            for(const e of this.tasks)
            {
                if( id != e.data.OwerID)
                {
                    continue;
                }
                for(const i of e.data.spawn_info)
                {
                    if(i.bodyconfig.Role == role)
                    {
                        count+=i.count;
                    }
                }
                break
            }
            return count;
        }
        return memory.spawnstats[role]? memory.spawnstats[role]:0
    }
     
    private incressRoleCount(role:RoleName,count:number)
    {
        const memory = this.getNodeMemory();
        if(memory.spawnstats[role])
        {
            memory.spawnstats[role]+=count;
        }
        else
        {
            memory.spawnstats[role]=count;
        }
        //this.log(`info`,'孵化数量增加',role,memory.spawnstats[role]);
    }
    private decressRoleCount(role:RoleName)
    {
        const memory = this.getNodeMemory();
        memory.spawnstats[role]--;
        if(memory.spawnstats[role]<0)
        {
            this.getNodeMemory().spawnstats = this.getSpawnStatus();
            this.log("error",`错误:孵化数量不可能为负数，需要重新检测更新缓存`);
           
        }
        //this.log(`info`,'孵化数量减少',role,memory.spawnstats[role]);
    }
    /**
     * 获取此房间正在孵化的统计信息
 
     * @param id 
     * @returns 
     */ 
    private getSpawnStatus( )
    {
        const spawnRecord:Record<string,number>={};
        for(const e of this.tasks)
        {
            for(const i of e.data.spawn_info)
            {
                if(spawnRecord[i.bodyconfig.Role])
                {
                    spawnRecord[i.bodyconfig.Role]+=i.count;
                }
                else
                {
                    spawnRecord[i.bodyconfig.Role]=i.count;
                }
            }
        }
        return spawnRecord;
    }
    

    /**
     * 搜索指定爬名的孵化任务
     */
     public searchSpawnTaskByCreepName(creepName: string): T | undefined {
        return this.tasks.find((task) => task.data && task.data.spawn_info.find(e=>e.creepName && e.creepName.includes(creepName)))
    }

    /**
     * 搜索指定角色的孵化任务
     */
    public searchSpawnTaskByRole(role:RoleName): T[] | undefined {
        const tasks = this.tasks.filter((task) => task.data.spawn_info.find(e=>e.bodyconfig.Role === role))
        return tasks.length > 0 ? tasks : []
    }

    public getSpawnDirections(spawn:StructureSpawn):DirectionConstant[]
    {
        const posstr = spawn.pos.x-this.BasePosition.x;
        return SpawnLayoutConfig.SpawmDirs[posstr];
    }
    /**
     * 堵死的时候给spawn腾出位置
     * @param spawn
     * @returns
     */
    public makeSpaceForSpawn(spawn:StructureSpawn)
    {

        const directions = this.getSpawnDirections(spawn);
        const pos = _.map(directions,e=>UtilsHelper.GetDirectionPos(spawn.pos,e))
        for(const e of pos)
        {
            const creeps = PositionHelper.lookFor(LOOK_CREEPS,e);
            if(creeps.length==0)
            {
                return true;
            }
        }

        for(const e of pos)
        {
            const creeps = PositionHelper.lookFor(LOOK_CREEPS,e);
            const nabpos = e.getFreeSpace(1,false,true);
            for(const nab of nabpos)
            {
                const nabcreeps = PositionHelper.lookFor(LOOK_CREEPS,nab);
                if(nabcreeps.length==0)
                {
                    // 有空闲位置.
                    
                    creeps[0]._move(creeps[0].pos.getDirectionTo(nab));
                    const direction=creeps[0].pos.getDirectionTo(nab);
                    creeps[0].say(`${direction}`)

                    break;
                }
            }
        }
        return false;
    }
    public getStoreObjects(type: IResource): AnyStoreStructure[] {
        const containerids = this.getStructuresByRelative(STRUCTURE_CONTAINER,SpawnLayoutConfig.containeridx,this.BasePosition);
        const store:AnyStoreStructure[] =[];
        for(const e of containerids)
        {
            const obj = Game.getObjectById(e);
            if(obj && obj?.store)
            {
                if(!type.amount || obj?.store.getFreeCapacity(type.resourceType)>=type.amount)
                {
                    store.push(obj);
                }
            }
        }
        return store;
    }
    public getWithdrawObjects(type: IResource): AnyStoreStructure[] 
    {
        const containerids = this.getStructuresByRelative(STRUCTURE_CONTAINER,SpawnLayoutConfig.containeridx,this.BasePosition);
        const store:AnyStoreStructure[] =[];
        for(const e of containerids)
        {
            const obj = Game.getObjectById(e);
            if(obj && obj?.store)
            {
                if(!type.amount || obj?.store.getUsedCapacity(type.resourceType)>=type.amount)
                {
                    store.push(obj);
                }
            }
        }
        return store;
    }
   
    /**
     * 用户孵化的spawn
     * @returns 
     */
    public spawnStructures(): StructureSpawn[]
    {
        return this.room.getStructures(STRUCTURE_SPAWN) 
        //return this.getStructuresByRelative(STRUCTURE_SPAWN,SpawnLayoutConfig.SpawnPos,this.BasePosition)

    }
    public get Link(): StructureLink | undefined
    {
        return Game.getObjectById( this.getStructuresByRelative(STRUCTURE_LINK,[SpawnLayoutConfig.LinkPos],this.BasePosition)[0]) as StructureLink | undefined
    }
    public getContainer():Id<StructureContainer>[]
    {
        return this.getStructuresByRelative(STRUCTURE_CONTAINER,SpawnLayoutConfig.containeridx,this.BasePosition)
    }

    public getContainePos():RoomPosition[]
    {
        return this._cacheContainerPos
        // return  SpawnLayoutConfig.containeridx.map(e=> this.getAbsulotePosition(e))
    }
  
    public getPickUpResource():Resource|undefined
    {
        if((this.room as any).spawnpickup)
        {
            return (this.room as any).spawnpickup 
        }
        const droppos = this.getContainePos();
       
        const resource = droppos[0].lookFor(LOOK_RESOURCES).filter(e=>e.resourceType == RESOURCE_ENERGY);
        (this.room as any).spawnpickup = resource[0];
        return (this.room as any).spawnpickup
    }
    /**
     * 用于ext 传输能量的spawn
     * 
     * @returns 
     */
    public transferStructures():  Id<StructureSpawn>[]
    {
        return this.getStructuresByRelative(STRUCTURE_SPAWN,SpawnLayoutConfig.transferSpawn,this.BasePosition)
    }

    /**
     * 注册填充爬
     * @param creep 
     * @returns 
     */
    public registerCreep(creep:Creep)
    {
        const memory = this.getNodeMemory();
        const key2name:Record<string,string> = {};
        for(const n of Object.keys(memory.filler))
        {
            if(Game.creeps[n])
            {
                key2name[memory.filler[n]]=n;
            }
            else
            {
                delete  memory.filler[n];
            }
        }
        for(const e of SpawnLayoutConfig.MiniCreepWorkPos)
        {
            
            const key = SpawnLayoutConfig.formatVector(e);
            const name = key2name[key];
            if(name && Game.creeps[name])
            {
                continue;
            }
            delete  memory.filler[name];
            memory.filler[creep.name] = key;
            return key;
        }
        return false;
    }

    public getWorkKey(creep:Creep)
    {
        return this.getNodeMemory().filler[creep.name]
    }

    /**
     * 填充工，根据自己的位置，获取需要填充的建筑
     * @param WorkPos 
     * @returns 
     */
    public  getTransferObject(workPos:IFVector2):AnyStoreStructure[]
    {
        const poskey =SpawnLayoutConfig.formatVector(workPos);
        const ids = this.getNodeMemory().workmap[poskey];
        if(!ids)
        {
            return [];
        }
        for(const e of ids)
        {
            const struct = Game.getObjectById(e) as AnyStoreStructure;
            if(struct.store.getFreeCapacity(RESOURCE_ENERGY)>0)
            {
                return [struct];
            }
        }
        return  []
    }
    public getSpawn(workPos:IFVector2)
    {
        const spawnPos = SpawnLayoutConfig.MiniQueenToSpawn[workPos.x][workPos.y];
        const spawn = this.getStructureByRelative(STRUCTURE_SPAWN,spawnPos,this.BasePosition)!
        return spawn?Game.getObjectById(spawn?.id)!:null
    }
    /**
     * 填充工，根据自己的位置，获取取能量的建筑
     * @param WorkPos 
     * @returns 
     */
    public getStoreObject(WorkPos:IFVector2,includeLink=true,filter:(arg:AnyStoreStructure)=>boolean=(arg:AnyStoreStructure)=>arg.store.getUsedCapacity(RESOURCE_ENERGY)>0):AnyStoreStructure[]
    {
        let withpos:IFVector2[]=SpawnLayoutConfig.getEnergyPos(WorkPos);
        // const basepos = {x:this.BasePosition.x+workPos.x,y:this.BasePosition.y+workPos.y};
        if(includeLink)
        {
            const links = this.getStructuresByRelative(STRUCTURE_LINK,[withpos[0]],this.BasePosition);
            for(const e of links)
            {
                const store =  Game.getObjectById(e);
                if(store && filter(store))
                {
                    return [store]
                }
            }
        }
        const containers = this.getStructuresByRelative(STRUCTURE_CONTAINER,[withpos[1]],this.BasePosition);
        for(const e of containers)
        {
            const store =  Game.getObjectById(e);
            if(store &&  filter(store))
            {
                return [store]
            }
        }
        return [];
    }



    public allocRenewSlot(creep:Creep)
    {
        if(creep.memory.spawn)
        {
            return false;
        }
     
        const nodeMemory = this.getNodeMemory();
        for(let spawnName in nodeMemory.renewSlot)
        {
            const creepName = nodeMemory.renewSlot[spawnName];
            if(!creepName || !Game.creeps[creepName] ||Game.creeps[creepName].room.name != this.roomName || Game.creeps[creepName].memory.IsBoosted ||(Game.creeps[creepName].ticksToLive&& Game.creeps[creepName].ticksToLive as number>1400))
            {
                nodeMemory.renewSlot[spawnName]=creep.name;
                creep.memory.spawn = spawnName;
                return true;
            }
        }
        return false;
    }

    public releaseRenewSlot(creep:Creep)
    {
        if(!creep.memory.spawn)
        {
            return false;
        }
        const nodeMemory = this.getNodeMemory();
        for(let spawnName in nodeMemory.renewSlot)
        {
            if(nodeMemory.renewSlot[spawnName] == creep.name)
            {
                nodeMemory.renewSlot[spawnName]=undefined;
                creep.memory.spawn = undefined;
                return true;
            }
        }
        return false;
    }

    private spliceSpawnInfo(spawnData:ISpawnData,index:number)
    {
        
         
        if( spawnData.spawn_info[index].creepName!.length ==0)
        {
            spawnData.spawn_info.splice(index,1);
        }
        else  if (spawnData.spawn_info[index].creepName!.length ==1)
        {
            spawnData.spawn_info[index].creepName!.splice(0,1);
            spawnData.spawn_info[index].count--;
            spawnData.spawn_info.splice(index,1);
        }
        else 
        {
            spawnData.spawn_info[index].creepName!.splice(0,1);
            spawnData.spawn_info[index].count--;
        }
            
    }
}
